package com.ifp.opengate.boot.utils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ifp.adapter.common.AdapterCanstants;
import com.ifp.core.context.ClogicContext;
import com.ifp.core.exception.BaseException;
import com.ifp.core.flow.util.IMessageUtil;
import com.ifp.core.log.Trace;
import com.ifp.core.util.DateUtil;
import com.ifp.core.util.StringUtil;
import com.ifp.gateway.handle.GatewayHandle;
import com.ifp.opengate.boot.bean.access.IPBlackAndWhiteBean;
import com.ifp.opengate.boot.constants.Constants;
import com.ifp.opengate.boot.emum.ErrorEnum;

/**
 * Copyright © 2018 ynet Info. Tech Ltd. All rights reserved.
 * 
 * @Description: 报文工具类
 * @author: 灭霸
 * @date: 2018年11月12日 上午10:06:56
 */
@Component("messageUtil")
public class MessageUtil implements IMessageUtil {
    /**
     * 网关处理器
     */
    @Autowired
    private GatewayHandle gwHandle;
    /**
     * 序列号（4位）
     */
    private static AtomicLong SEQ = new AtomicLong(1000);
    /**
     * 字符编码
     */
    private final static String ENCODING = "UTF-8";
    /**
     * 系统编号
     */
    private final static String OGW = "OGW";
    /**
     * 行内系统流水号标识
     */
    private final static String OPB = "OPB";
    /**
     * 6个蛋
     */
    private final static String SIX_ZERO = "000000";
    /**
     * 时间格式
     */
    private final static String TIME_FORMAT = "yyyyMMddHHmmssSSS";

    @Autowired
    IPBlackAndWhiteBean ipBlackAndWhiteBean;

    @Autowired
    private UniErrCodeUtils uniErrCodeUtils;

    /**
     * 获取行内通讯报文头
     * 
     * @return
     */
    public Map<String, Object> getInnerHeadMap(String transGlobalFlow) {
        Map<String, Object> headMap = new HashMap<String, Object>();
        headMap.put("systemID", OGW);
        headMap.put("srcSystemID", OGW);
        // 内部系统交易时间 yyyyMMddhhmmss
        String dateTime = DateUtil.getStringToday();
        headMap.put("transDate", dateTime.substring(1, 8));
        headMap.put("transTime", dateTime.substring(8, 14));
        headMap.put("transGlobalFlow", transGlobalFlow);
        // transGlobalFlow 已经唯一，补零即可
        headMap.put("transFlow", transGlobalFlow + OPB + SIX_ZERO);
        // transGlobalFlow 已经唯一，补零即可
        headMap.put("channelTransFlow", transGlobalFlow + OPB + SIX_ZERO);

        return headMap;
    }

    /**
     * 获取行内系统通讯全局流水(线程安全)
     */
    public String getTransGlobalFlow() throws BaseException {
        if (SEQ.get() >= 9999) {
            SEQ.set(1000);
        }
        return OPB + "G01" + DateUtil.getStringToday() + SEQ.getAndIncrement();
    }

    public void getResponseHeader(Map<String, Object> headerMap, BaseException baseException,
        ClogicContext clogicContext) {
        String errorCode = (String)headerMap.get(com.ifp.core.base.Constants.ERRORCODE);
        String errorMsg = (String)headerMap.get(com.ifp.core.base.Constants.ERRORMSG);
        if (null != baseException) {
            errorCode = baseException.getErrorCode();
            errorMsg = baseException.getErrorMessage();
            headerMap.put(com.ifp.core.base.Constants.ERRORCODE, errorCode);
            headerMap.put(com.ifp.core.base.Constants.ERRORMSG, errorMsg);
            // 商户号
            String appId = (String)headerMap.get("appId");
            String responseTime = DateUtil.getUserDate("yyyyMMddHHmmssSSS");
            headerMap.put(Constants.RESPONSE_TIME, responseTime);
            // 创建标准响应报文头
            ResponseUtil.createStandardResponseHeader(headerMap);

            try {
                // 白名单拦截
                if (!WhiteListCaheUtil.getCacheCheckWhiteFromBean(ipBlackAndWhiteBean.getAppWhtelist(), appId,
                    "CipherFilter", clogicContext)) {
                    // TODO 添加加签操作
                }
            } catch (BaseException e) {
                Trace.logInfo(Trace.MODULE_INTERCEPTOR, "Base64 加密失败.", e);
            }
        } else {
            // 成功
            errorCode = ErrorEnum.success.code();
            errorMsg = ErrorEnum.success.msg();
        }

        headerMap.put(com.ifp.core.base.Constants.ERRORCODE, errorCode);
        headerMap.put(com.ifp.core.base.Constants.ERRORMSG, errorMsg);

    }

    /**
     * 错误返回报文组装
     * 
     * @param outputDataMap
     */
    @Override
    public void getResponseDataMap(Map<String, Object> outputDataMap, ClogicContext clogicContext,
        BaseException baseException) {

        Map<String, Object> headerMap = (Map<String, Object>)outputDataMap.get(AdapterCanstants.HEADER);
        // 请求模式：A-开放平台标准接口，O-提供给内部系统的接口，M-旧外联接口
        // 全局错误码映射
        errorCodeMappingHandler(clogicContext, baseException, headerMap);
        // ==================
        String requestType = null;
        if (clogicContext != null) {
            requestType = clogicContext.getRequestType();
        }
        if (Constants.REQUEST_TYPE_O.equalsIgnoreCase(requestType)) {
            headerMap.remove(Constants.REQUEST_TIME);
            // 内部系统
            headerMap.put(Constants.RESPONSE_TIME, DateUtil.getUserDate(TIME_FORMAT));
            return;
        } else {
            // 新接入商户，api标准用户
            getResponseHeader(headerMap, baseException, clogicContext);
            // 组装返回header
            outputDataMap.put(AdapterCanstants.HEADER, headerMap);
            // outputDataMap.put(AdapterCanstants.HEADER, codeInfo);
            if (null != baseException) {
                // 组装返回body为空
                outputDataMap.put(AdapterCanstants.BODY, "");
            }
        }
    }

    private void errorCodeMappingHandler(ClogicContext clogicContext, BaseException baseException,
        Map<String, Object> headerMap) {
        String apiCodeVer = null;
        String apiCode = null;
        String errorCode = getMessageInfo(headerMap, clogicContext, Constants.ERROR_CODE);
        String errorMsg = getMessageInfo(headerMap, clogicContext, Constants.ERROR_MSG);
        String apiVersion = getMessageInfo(headerMap, clogicContext, Constants.VERSION);
        String sysCode = getMessageInfo(headerMap, clogicContext, Constants.SUBCRIBE_SYSTEM_ID);
        String channel = getMessageInfo(headerMap, clogicContext, Constants.APP_ID);
        if (clogicContext.transCode != null) {
            apiCode = clogicContext.transCode;
        }
        if (StringUtil.hasText(apiCode) && StringUtil.hasText(apiVersion)) {
            apiCodeVer = apiCode + "_" + apiVersion;
        }
        Map codeInfo = uniErrCodeUtils.getUniErrCodeInfo(errorCode, errorMsg, apiCodeVer, sysCode, channel);
        if (codeInfo != null && codeInfo.size() > 0) {
            headerMap.put(Constants.ERROR_CODE, codeInfo.get(Constants.ERROR_CODE));
            headerMap.put(Constants.ERROR_MSG, codeInfo.get(Constants.ERROR_MSG));
            baseException.setErrorCode((String)codeInfo.get(Constants.ERROR_CODE));
            baseException.setErrorMessage((String)codeInfo.get(Constants.ERROR_MSG));
        }
    }

    private String getMessageInfo(Map<String, Object> headerMap, ClogicContext clogicContext, String miKey) {
        if (headerMap == null || clogicContext == null || miKey == null) {
            return null;
        }
        String message = (String)headerMap.get(miKey);
        if (!StringUtil.hasText(message)) {
            if (clogicContext.dataMap != null) {
                Map<String, Object> headdataMap =
                    (Map<String, Object>)clogicContext.dataMap.get(AdapterCanstants.HEADER);
                message = (String)headdataMap.get(miKey);
            }
        }
        if (!StringUtil.hasText(message)) {
            if (clogicContext.dataMap != null) {
                Map<String, Object> bodydataMap = (Map<String, Object>)clogicContext.dataMap.get(AdapterCanstants.BODY);
                message = (String)bodydataMap.get(miKey);
            }
        }
        return message;
    }
}
